package com.slunk.physics.characters;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Filter;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.graphics.Texture;
import com.slunk.utilities.Movement;

public class Character {
	protected World world;
	protected Sprite sprite;
	protected Movement currentState;
	protected float speed;
	protected Body body;
	protected float width;
	protected float height;
	protected int point_modifier = 1;
	protected float speed_modifier = 0.0f;
	protected float screenWidth = 0.0f;
	protected float screenHeight = 0.0f;
	
	public Character (World world, Vector2 position, float boxWidth, float boxHeight, Short categoryBits, Short maskBits) {
		this.world = world;
		this.body = createCharacter(position,boxWidth,boxHeight);
		this.speed = 1.0f;
		this.width = boxWidth;
		this.height = boxHeight;
		
		//not necessary to have but will include anyways
		
		if (categoryBits != null || maskBits != null) {
			Filter filter = new Filter();
			
			if (categoryBits != null) {
				filter.categoryBits = categoryBits;
			}
			if (maskBits != null) {
				filter.maskBits = maskBits;
			}
			this.getCharacterBody().getFixtureList().get(0).setFilterData(filter);
		}
	}
	
	public void setScreenSize(float screenWidth, float screenHeight) {
		this.screenWidth = screenWidth;
		this.screenHeight = screenHeight;
	}

	public void setSprite(Sprite sprite) {
		this.sprite = sprite;
	}
	public void setSprite(Texture texture) {
		this.setSprite(new Sprite(texture));
	}
	public void setSprite(String filename) {
		this.setSprite(new Texture(Gdx.files.internal(filename)));
	}
	
	public Sprite getSprite() {
		return this.sprite;
	}
	
	public void drawSprite(SpriteBatch batch) {
		if (this.sprite != null) {
			this.updatePosition();
			this.sprite.draw(batch);
		}
	}
	
	private void updatePosition() {
		Vector2 bodyPosition = this.getCharacterPosition();
		this.sprite.setPosition(bodyPosition.x - this.sprite.getWidth()/2, bodyPosition.y - this.sprite.getHeight()/2);
	}
	
	
	public Character(World world, Vector2 position, float boxWidth, float boxHeight) {
		this(world,position,boxWidth,boxHeight,null,null);
	}
	
	public Body getCharacterBody() {
		return this.body;
	}
	
	//This method is assumed to be invoked after batch.start and before.end
	public void draw(SpriteBatch batch) {
		this.sprite.draw(batch);
	}
	
	//get position of the character
	public Vector2 getCharacterPosition() {
		return this.body.getPosition();
	}
	
	//Set the position of the character
	public void setCharacterPosition (Vector2 position) {
		this.body.setTransform(position, 0.0f);
	}
	
	public void resetCharacterModifiers() {
		this.point_modifier = 1;
		this.speed_modifier = 0.0f;
	}
	
	public void setPointModifier(int point_modifier) {
		this.point_modifier = point_modifier;
	}
	public void setSpeedModifier(float speed_modifier) {
		this.speed_modifier = this.speed_modifier + speed_modifier;
	}
	
	public int getPointModifier() {
		return this.point_modifier;
	}
	
	public float getSpeed() {
		return this.speed + this.speed_modifier;
	}
	
	public void setSpeed (float speed) {
		this.speed = speed;
	}
	
	public void setMovementState (Movement state) {
		this.currentState = state;
	}
	
	public Movement getCurrentState() {
		return this.currentState;
	}
	
	public void updateMovement() {
		Vector2 oldPosition = this.body.getPosition();
		Vector2 newPosition = null;

		switch(this.currentState){
		case EAST: {
			newPosition = new Vector2(oldPosition.x + this.getSpeed()/*this.speed*/, oldPosition.y);
			break;
		}
		case NORTH: {
			newPosition = new Vector2(oldPosition.x, oldPosition.y + this.getSpeed()/*this.speed*/);
			break;
		}
		case NORTHEAST: {
			newPosition = new Vector2(oldPosition.x + this.getSpeed()/*this.speed*/, oldPosition.y + this.getSpeed()/*this.speed*/);
			break;
		}
		case NORTHWEST: {
			newPosition = new Vector2(oldPosition.x - this.getSpeed()/*this.speed*/, oldPosition.y + this.getSpeed()/*this.speed*/);
			break;
		}
		case SOUTH: {
			newPosition = new Vector2(oldPosition.x, oldPosition.y - this.getSpeed()/*this.speed*/);
			break;	
		}
		case SOUTHEAST: {
			newPosition = new Vector2(oldPosition.x + this.getSpeed()/*this.speed*/, oldPosition.y - this.getSpeed()/*this.speed*/);
			break;
		}
		case SOUTHWEST: {
			newPosition = new Vector2(oldPosition.x - this.getSpeed()/*this.speed*/, oldPosition.y - this.getSpeed()/*this.speed*/);
			break;
		}
		case STILL: {
			break;
		}
		case WEST: {
			newPosition = new Vector2(oldPosition.x - this.getSpeed()/*this.speed*/, oldPosition.y);
			break;
		}
		default:
			break;
		}
		
		if (newPosition != null) {
			
			if (this.screenWidth != 0.0f && this.screenHeight != 0.0f) {
				if (newPosition.x - this.width / 2 <= 0) {
					newPosition.x = this.width;
				} else if (newPosition.x + this.width / 2 >= this.screenWidth) {
					newPosition.x = this.screenWidth - this.width;
				}
				
				if (newPosition.y - this.height / 2 <= 0) {
					newPosition.y = this.height;
				} else if (newPosition.y + this.height / 2 >= this.screenHeight) {
					newPosition.y = this.screenHeight - this.height;
				}
			}
			setCharacterPosition(newPosition);
		}
	}
	
	public float getWidth() {
		return this.width;
	}
	
	public float getHeight() {
		return this.height;
	}
	
	private Body createCharacter(Vector2 position, float width, float height) {
		BodyDef bodyDef = new BodyDef();
		bodyDef.type = BodyDef.BodyType.DynamicBody;
		bodyDef.position.set(position);
		Body body = this.world.createBody(bodyDef);
		
		PolygonShape box = new PolygonShape();
		box.setAsBox(width, height);

		body.createFixture(box, 0.0f);
		return body;
	}
}
